// Zombie Monster for KF Invasion gametype
class EXZombieBoss extends EXZombieBossBase;

#exec OBJ LOAD FILE=KFPatch2.utx
#exec OBJ LOAD FILE=KF_Specimens_Trip_T.utx

//----------------------------------------------------------------------------
// NOTE: Most Variables are declared in the base class to eliminate hitching
//----------------------------------------------------------------------------

var BossHPNeedle CurrentNeedle;

// Make the Boss's ambient scale higher, since there is only 1, doesn't matter if he's relevant almost all the time
simulated function CalcAmbientRelevancyScale()
{
		// Make the zed only relevant by thier ambient sound out to a range of 100 meters
		CustomAmbientRelevancyScale = 5000/(100 * SoundRadius);
}

function ZombieMoan()
{
	if( !bShotAnim ) // Do not moan while taunting
		Super.ZombieMoan();
}

// Speech notifies called from the anims
function PatriarchKnockDown()
{
	PlaySound(SoundGroup'KF_EnemiesFinalSnd.Patriarch.Kev_KnockedDown', SLOT_Misc, 2.0,true,500.0);
	//PlaySound(SoundGroup'KF_EnemiesFinalSnd_Xmas.Patriarch.Kev_KnockedDown', SLOT_Misc, 2.0,true,500.0);
}

function PatriarchEntrance()
{
	PlaySound(SoundGroup'KF_EnemiesFinalSnd.Patriarch.Kev_Entrance', SLOT_Misc, 2.0,true,500.0);
	//PlaySound(SoundGroup'KF_EnemiesFinalSnd_Xmas.Patriarch.Kev_Entrance', SLOT_Misc, 2.0,true,500.0);
}

function PatriarchVictory()
{
	PlaySound(SoundGroup'KF_EnemiesFinalSnd.Patriarch.Kev_Victory', SLOT_Misc, 2.0,true,500.0);
	//PlaySound(SoundGroup'KF_EnemiesFinalSnd_Xmas.Patriarch.Kev_Victory', SLOT_Misc, 2.0,true,500.0);
}

function PatriarchMGPreFire()
{
	PlaySound(SoundGroup'KF_EnemiesFinalSnd.Patriarch.Kev_WarnGun', SLOT_Misc, 2.0,true,1000.0);
	//PlaySound(SoundGroup'KF_EnemiesFinalSnd_Xmas.Patriarch.Kev_WarnGun', SLOT_Misc, 2.0,true,1000.0);
}

function PatriarchMisslePreFire()
{
	PlaySound(SoundGroup'KF_EnemiesFinalSnd.Patriarch.Kev_WarnRocket', SLOT_Misc, 2.0,true,1000.0);
	//PlaySound(SoundGroup'KF_EnemiesFinalSnd_Xmas.Patriarch.Kev_WarnRocket', SLOT_Misc, 2.0,true,1000.0);
}

// Don't do this for the Patriarch
simulated function SetBurningBehavior(){}
simulated function UnSetBurningBehavior(){}
function bool CanGetOutOfWay()
{
	return false;
}

simulated function Tick(float DeltaTime)
{
	local SRKFHumanPawn HP;
		local int tmp_CloakMode;

	Super.Tick(DeltaTime);

	// Process the pipe bomb time damage scale, reducing the scale over time so
	// it goes back up to 100% damage over a few seconds
	if( Role == ROLE_Authority )
	{
		PipeBombDamageScale -= DeltaTime * 0.33;
		if( PipeBombDamageScale < 0 )
		{
			PipeBombDamageScale = 0;
		}
	}

	if( Level.NetMode==NM_DedicatedServer )
		return; // Servers aren't intrested in this info.

	bSpecialCalcView = bIsBossView;
	if( bCloaked && Level.TimeSeconds>LastCheckTimes )
	{
		LastCheckTimes = Level.TimeSeconds+0.8;
		foreach VisibleCollidingActors(Class'SRKFHumanPawn',HP,1000,Location)
		{
			if(	HP != none && HP.Health > 0 && 
				(((HP.ShowStalkers() || (HP.ShowStalkersEx() > 0 && HP.ShowStalkersEx() < 4)) &&
				(VSizeSquared(Location - HP.Location) < HP.GetStalkerViewDistanceMulti() * 640000.0)) || HP.ShowStalkersEx() > 3) 
			  )
			{
				if (HP.ShowStalkersEx() == 2 || HP.ShowStalkersEx() == 4)
					tmp_CloakMode = 1;
				else if (HP.ShowStalkersEx() == 3 || HP.ShowStalkersEx() == 5)
					tmp_CloakMode = 2;
				else
					tmp_CloakMode = 0;
			}
			else
				continue;

			// If he's a commando, we've been spotted.
			if( !bSpotted )
			{
				bSpotted = True;
				CloakBoss(tmp_CloakMode);
			}
			return;
		}
		// if we're uberbrite, turn down the light
		if( bSpotted )
		{
			bSpotted = False;
			bUnlit = false;
			CloakBoss(tmp_CloakMode);
		}
	}
}

simulated function CloakBoss(int CloakMode)
{
	local Controller C;
	local int Index;

	if( bSpotted )
	{
		Visibility = 120;
		if( Level.NetMode==NM_DedicatedServer )
			return;
		if (CloakMode > 0)
		{
			Skins = Default.Skins;
			if (PlayerShadow != none)
				PlayerShadow.bShadowActive = true;

			bAcceptsProjectors = true;
			if (CloakMode == 1) /* Flickering Boss */
				SetOverlayMaterial( none, 0.0, true );
			bUnlit = false;
		}
		else
		{
			Skins[0] = Finalblend'KFX.StalkerGlow';
			Skins[1] = Finalblend'KFX.StalkerGlow';
			bUnlit = true;
		}
		return;
	}

	Visibility = 1;
	bCloaked = true;
	if( Level.NetMode!=NM_Client )
	{
		for( C=Level.ControllerList; C!=None; C=C.NextController )
		{
			if( C.bIsPlayer && C.Enemy==Self )
				C.Enemy = None; // Make bots lose sight with me.
		}
	}
	if( Level.NetMode==NM_DedicatedServer )
		return;

	Skins[0] = Shader'KF_Specimens_Trip_T.patriarch_invisible_gun';
	Skins[1] = Shader'KF_Specimens_Trip_T.patriarch_invisible';
	//Skins[1] = Shader'KF_Specimens_Trip_T.patriarch_invisible_gun';
	//Skins[0] = Shader'KF_Specimens_Trip_XMAS_T.patriarch_Santa.patriarch_santa_invisible_shdr';

	// Invisible - no shadow
	if(PlayerShadow != none)
		PlayerShadow.bShadowActive = false;

	// Remove/disallow projectors on invisible people
	Projectors.Remove(0, Projectors.Length);
	bAcceptsProjectors = false;
	SetOverlayMaterial(FinalBlend'KF_Specimens_Trip_T.patriarch_fizzle_FB', 1.0, true);

	// Randomly send out a message about Patriarch going invisible(10% chance)
	if ( FRand() < 0.10 )
	{
		// Pick a random Player to say the message
		Index = Rand(Level.Game.NumPlayers);

		for ( C = Level.ControllerList; C != none; C = C.NextController )
		{
			if ( PlayerController(C) != none )
			{
				if ( Index == 0 )
				{
					PlayerController(C).Speech('AUTO', 8, "");
					break;
				}

				Index--;
			}
		}
	}
}

simulated function UnCloakBoss()
{
	Visibility = default.Visibility;
	bCloaked = false;
	bSpotted = False;
	bUnlit = False;
	if( Level.NetMode==NM_DedicatedServer )
		return;
	Skins = Default.Skins;

	if (PlayerShadow != none)
		PlayerShadow.bShadowActive = true;

	bAcceptsProjectors = true;
	SetOverlayMaterial( none, 0.0, true );
}

//-----------------------------------------------------------------------------
// PostBeginPlay
//-----------------------------------------------------------------------------

simulated function PostBeginPlay()
{
	Super.PostBeginPlay();

	if( Role < ROLE_Authority )
	{
		return;
	}

	// Difficulty Scaling
	if (Level.Game != none)
	{
		//log(self$" Beginning ground speed "$default.GroundSpeed);

		// If you are playing by yourself,  reduce the MG damage
		if( Level.Game.NumPlayers == 1 )
		{
			if( Level.Game.GameDifficulty < 2.0 )
			{
				MGDamage = default.MGDamage * 0.375;
			}
			else if( Level.Game.GameDifficulty < 4.0 )
			{
				MGDamage = default.MGDamage * 0.75;
			}
			else if( Level.Game.GameDifficulty < 5.0 )
			{
				MGDamage = default.MGDamage * 1.15;
			}
			else // Hardest difficulty
			{
				MGDamage = default.MGDamage * 1.3;
			}
		}
		else
		{
			if( Level.Game.GameDifficulty < 2.0 )
			{
				MGDamage = default.MGDamage * 0.375;
			}
			else if( Level.Game.GameDifficulty < 4.0 )
			{
				MGDamage = default.MGDamage * 1.0;
			}
			else if( Level.Game.GameDifficulty < 5.0 )
			{
				MGDamage = default.MGDamage * 1.15;
			}
			else // Hardest difficulty
			{
				MGDamage = default.MGDamage * 1.3;
			}
		}
	}

	HealingLevels[0] = Health / 1.25; // Around 5600 HP
	HealingLevels[1] = Health / 2.f; // Around 3500 HP
	HealingLevels[2] = Health / 3.2; // Around 2187 HP
	HealingLevels[3] = Health / 4.32;
	HealingLevels[4] = Health / 5.4;
	HealingLevels[5] = Health / 6.5;
	HealingLevels[6] = Health / 7.6;
	MissilesToShootInARow = 2 + rand(5);
//	log("Health = "$Health);
//	log("HealingLevels[0] = "$HealingLevels[0]);
//	log("HealingLevels[1] = "$HealingLevels[1]);
//	log("HealingLevels[2] = "$HealingLevels[2]);

	HealingAmount = Health/3;
//	log("HealingAmount = "$HealingAmount);
}

function bool MakeGrandEntry()
{
	bShotAnim = true;
	Acceleration = vect(0,0,0);
	SetAnimAction('Entrance');
	HandleWaitForAnim('Entrance');
	GotoState('MakingEntrance');

	return True;
}

// State of playing the initial entrance anim
state MakingEntrance
{
	Ignores RangedAttack;

	function Tick( float Delta )
	{
		Acceleration = vect(0,0,0);

		Global.Tick(Delta);
	}

Begin:
	Sleep(GetAnimDuration('Entrance'));
	GotoState('InitialSneak');
}

simulated function Destroyed()
{
	if( mTracer!=None )
		mTracer.Destroy();
	if( mMuzzleFlash!=None )
		mMuzzleFlash.Destroy();
	Super.Destroyed();
}

simulated Function PostNetBeginPlay()
{
	EnableChannelNotify ( 1,1);
	AnimBlendParams(1, 1.0, 0.0,, SpineBone1);
	Super.PostNetBeginPlay();
	TraceHitPos = vect(0,0,0);
	bNetNotify = True;
}

function PlayTakeHit(vector HitLocation, int Damage, class<DamageType> DamageType)
{
	if( Level.TimeSeconds - LastPainAnim < MinTimeBetweenPainAnims )
		return;

	if(	Damage>=150 || (DamageType.name=='DamTypeStunNade' && rand(5)>3) || 
		(DamageType.name=='DamTypeCrossbowHeadshot' && Damage>=200) )
		PlayDirectionalHit(HitLocation);

	LastPainAnim = Level.TimeSeconds;

	if( Level.TimeSeconds - LastPainSound < MinTimeBetweenPainSounds )
		return;

	LastPainSound = Level.TimeSeconds;
	PlaySound(HitSound[0], SLOT_Pain,2*TransientSoundVolume,,400);
}

function bool OnlyEnemyAround( Pawn Other )
{
	local Controller C;

	For( C=Level.ControllerList; C!=None; C=C.NextController )
	{
		if( C.bIsPlayer && C.Pawn!=None && C.Pawn!=Other && ((VSize(C.Pawn.Location-Location)<1500 && FastTrace(C.Pawn.Location,Location))
		|| (VSize(C.Pawn.Location-Other.Location)<1000 && FastTrace(C.Pawn.Location,Other.Location))) )
			return False;
	}
	return True;
}

function bool IsCloseEnuf( Actor A )
{
	local vector V;

	if( A==None )
		return False;
	V = A.Location-Location;
	if( Abs(V.Z)>(CollisionHeight+A.CollisionHeight) )
		return False;
	V.Z = 0;
	return (VSize(V)<(CollisionRadius+A.CollisionRadius+25));
}

function RangedAttack(Actor A)
{
	local float D;
	local bool bOnlyE;
	local bool bDesireChainGun;
	local bool bDesireSurroundingPlayersMisslesAttack;

	// Randomly make him want to chaingun more
	if( Controller.LineOfSightTo(A) && FRand() < 0.75 && LastChainGunTime<Level.TimeSeconds )
	{
		bDesireChainGun = true;
	}
	bDesireSurroundingPlayersMisslesAttack = false;

	if ( bShotAnim )
		return;
	D = VSize(A.Location-Location);
	bOnlyE = (Pawn(A)!=None && OnlyEnemyAround(Pawn(A)));

	if (IsCloseEnuf(A) && Pawn(A)!=None && !OnlyEnemyAround(Pawn(A)))
	{
		if (FRand() < 0.65)
			bDesireSurroundingPlayersMisslesAttack = true;
		else
			bDesireChainGun = true;
	}

	if (	IsCloseEnuf(A) && Pawn(A)!=None && OnlyEnemyAround(Pawn(A)) && 
			!bDesireSurroundingPlayersMisslesAttack && !bDesireChainGun ) 
			/* Use melee attack if the player is only one near the Boss. For many players surrounding use much more effective melee weapons */
	{
		bShotAnim = true;
		if( Health>HealthMax/10 && Pawn(A)!=None && FRand() < 0.5 )
		{
			SetAnimAction('MeleeImpale');
		}
		else
		{
			SetAnimAction('MeleeClaw');
			//PlaySound(sound'Claw2s', SLOT_None); KFTODO: Replace this
		}
	}
	else if( Level.TimeSeconds - LastSneakedTime > 20.0 )
	{
		if( FRand() < 0.3 )
		{
			// Wait another 20 to try this again
			LastSneakedTime = Level.TimeSeconds;//+FRand()*120;
			return;
		}
		SetAnimAction('transition');
		GoToState('SneakAround');
	}
	else if(	bChargingPlayer && (bOnlyE || D<200) && !bDesireChainGun && 
				!bDesireSurroundingPlayersMisslesAttack )
		return;
	else if(	!bDesireChainGun && !bDesireSurroundingPlayersMisslesAttack && 
				!bChargingPlayer && (D<300 || (D<700 && bOnlyE)) &&
				(Level.TimeSeconds - LastChargeTime > (5.0 + 5.0 * FRand())) )  
				// Don't charge again for a few seconds
	{
		SetAnimAction('transition');
		GoToState('Charging');
	}
	else if( ((LastMissileTime<Level.TimeSeconds) && D > 500 ) || bDesireSurroundingPlayersMisslesAttack )
	{
		if (MissilesToShootInARow <= 0)
		{
			NumMissilesToShootInARow = 2 + rand(5);
			MissilesToShootInARow = NumMissilesToShootInARow;
		}
		if( !Controller.LineOfSightTo(A) || FRand() > 0.75 )
		{
			LastMissileTime = Level.TimeSeconds+FRand() * 5;
			return;
		}

		LastMissileTime = Level.TimeSeconds + 10 + FRand() * 15;
		bShotAnim = true;
		Acceleration = vect(0,0,0);
		SetAnimAction('PreFireMissile');
		HandleWaitForAnim('PreFireMissile');
		GoToState('FireMissile');
	}
	else if ( !bWaitForAnim && !bShotAnim && LastChainGunTime<Level.TimeSeconds )
	{
		if ( !Controller.LineOfSightTo(A) || FRand()> 0.85 )
		{
			LastChainGunTime = Level.TimeSeconds + 4 + FRand()*3;
			return;
		}

		LastChainGunTime = Level.TimeSeconds + 5 + FRand() * 7;
		bShotAnim = true;
		//Acceleration = vect(0,0,0);
		Acceleration = (A.Location-Location);
		SetAnimAction('PreFireMG');
		HandleWaitForAnim('PreFireMG');
		MGFireCounter =  Rand(60) + 60;
		GoToState('FireChaingun');
	}
}

event Bump(actor Other)
{
	Super(Monster).Bump(Other);
	if( Other==none )
		return;

	if(	Other.IsA('NetKActor') && Physics != PHYS_Falling && !bShotAnim && 
		Abs(Other.Location.Z-Location.Z)<(CollisionHeight+Other.CollisionHeight) )
	{ // Kill the annoying deco brat.
		Controller.Target = Other;
		Controller.Focus = Other;
		bShotAnim = true;
		Acceleration = (Other.Location-Location);
		SetAnimAction('MeleeClaw');
		//PlaySound(sound'Claw2s', SLOT_None);  KFTODO: Replace this
		HandleWaitForAnim('MeleeClaw');
	}
}

simulated function AddTraceHitFX( vector HitPos )
{
	local vector Start,SpawnVel,SpawnDir;
	local float hitDist;

	Start = GetBoneCoords('tip').Origin;
	if( mTracer==None )
		mTracer = Spawn(Class'KFMod.KFNewTracer',,,Start);
	else mTracer.SetLocation(Start);
	if( mMuzzleFlash==None )
	{
		// KFTODO: Replace this
		mMuzzleFlash = Spawn(Class'MuzzleFlash3rdMG');
		AttachToBone(mMuzzleFlash, 'tip');
	}
	else mMuzzleFlash.SpawnParticle(1);
	hitDist = VSize(HitPos - Start) - 50.f;

	if( hitDist>10 )
	{
		SpawnDir = Normal(HitPos - Start);
		SpawnVel = SpawnDir * 10000.f;
		mTracer.Emitters[0].StartVelocityRange.X.Min = SpawnVel.X;
		mTracer.Emitters[0].StartVelocityRange.X.Max = SpawnVel.X;
		mTracer.Emitters[0].StartVelocityRange.Y.Min = SpawnVel.Y;
		mTracer.Emitters[0].StartVelocityRange.Y.Max = SpawnVel.Y;
		mTracer.Emitters[0].StartVelocityRange.Z.Min = SpawnVel.Z;
		mTracer.Emitters[0].StartVelocityRange.Z.Max = SpawnVel.Z;
		mTracer.Emitters[0].LifetimeRange.Min = hitDist / 10000.f;
		mTracer.Emitters[0].LifetimeRange.Max = mTracer.Emitters[0].LifetimeRange.Min;
		mTracer.SpawnParticle(1);
	}
	Instigator = Self;

	if( HitPos != vect(0,0,0) )
	{
		Spawn(class'ROBulletHitEffect',,, HitPos, Rotator(Normal(HitPos - Start)));
	}
}

simulated function AnimEnd( int Channel )
{
	local name  Sequence;
	local float Frame, Rate;

	if( Level.NetMode==NM_Client && bMinigunning )
	{
		GetAnimParams( Channel, Sequence, Frame, Rate );

		if( Sequence != 'PreFireMG' && Sequence != 'FireMG' )
		{
			Super.AnimEnd(Channel);
			return;
		}

		PlayAnim('FireMG');
		bWaitForAnim = true;
		bShotAnim = true;
		IdleTime = Level.TimeSeconds;
	}
	else Super.AnimEnd(Channel);
}

state FireChaingun
{
	function RangedAttack(Actor A)
	{
		Controller.Target = A;
		Controller.Focus = A;
	}

	// Chaingun mode handles this itself
	function bool ShouldChargeFromDamage()
	{
		return false;
	}

	function TakeDamage( int Damage, Pawn InstigatedBy, Vector Hitlocation, Vector Momentum, class<DamageType> damageType, optional int HitIndex)
	{
		//local PlayerDamageStruct PDS;
		//local int i;
		//local bool isNewElement;
		local float oldH, oldHH;

		local float EnemyDistSq, DamagerDistSq;
		//isNewElement=true;
/* 		PDS.PlayerName=InstigatedBy.Controller.PlayerReplicationInfo.PlayerName;
		PDS.Damage=Damage; */
	//PlayerDamageStructArray.Insert(PDS);
	
/* 		for(i=0;i<PlayerDamageStructArray.Length;i++)
		{
			if(PlayerDamageStructArray[i].PlayerName==PDS.PlayerName)
			{
				PlayerDamageStructArray[i].Damage+=PDS.Damage;
				isNewElement=false;
			}
		} */
	
		//if(isNewElement && Len(PDS.PlayerName)>0)
		//{
		//	PlayerDamageStructArray[PlayerDamageStructArray.Length]=PDS;
		//}
		
		oldH=Health;
		oldHH=HeadHealth;
		//Log(self$"   HealthBefore0="$Health$"   HeadHealthBefore0="$HeadHealth);
		//Log("PatD2="$Damage);
		//Log("Ex TakeDamage0="$damageType@Damage);
		Global.TakeDamage(Damage,instigatedBy,hitlocation,vect(0,0,0),damageType);
		//Log("HealthTaken0="$oldH-Health$"   HeadHealthTaken0="$oldHH-HeadHealth);
		// if someone close up is shooting us, just charge them
		if( InstigatedBy != none )
		{
			DamagerDistSq = VSizeSquared(Location - InstigatedBy.Location);

			if( (ChargeDamage > HealthMax/10 && DamagerDistSq < (300 * 300)) || DamagerDistSq < (150 * 150) )
			{
				SetAnimAction('transition');
				//log("Frak this shizz, Charging!!!!");
				GoToState('Charging');
				return;
			}
		}

		if(	Controller!=None && Controller.Enemy != none && InstigatedBy != none && 
			InstigatedBy != Controller.Enemy )
		{
			EnemyDistSq = VSizeSquared(Location - Controller.Enemy.Location);
			DamagerDistSq = VSizeSquared(Location - InstigatedBy.Location);
		}

		if(	Controller!=None && InstigatedBy != none && 
			(DamagerDistSq < EnemyDistSq || Controller.Enemy == none) )
		{
			MonsterController(Controller).ChangeEnemy(InstigatedBy,Controller.CanSee(InstigatedBy));
			Controller.Target = InstigatedBy;
			Controller.Focus = InstigatedBy;

			if( DamagerDistSq < (2000 * 2000) )
			{
				SetAnimAction('transition');
				GoToState('Charging');
			}
		}
	}

	function EndState()
	{
		TraceHitPos = vect(0,0,0);
		bMinigunning = False;

		AmbientSound = default.AmbientSound;
		SoundVolume=default.SoundVolume;
		SoundRadius=default.SoundRadius;
		MGFireCounter=0;

		LastChainGunTime = Level.TimeSeconds + 5 + (FRand()*3);
	}

	function BeginState()
	{
		bFireAtWill = False;
		//Acceleration = vect(0,0,0);
		MGLostSightTimeout = 0.0;
		bMinigunning = True;
	}

	function AnimEnd( int Channel )
	{
		if( MGFireCounter <= 0 )
		{
			bShotAnim = true;
						//Acceleration = vect(0,0,0);
			SetAnimAction('FireEndMG');
			HandleWaitForAnim('FireEndMG');
			GoToState('');
		}
		else
		{
			if ( Controller.Enemy != none )
			{
				if ( Controller.LineOfSightTo(Controller.Enemy) && FastTrace(GetBoneCoords('tip').Origin,Controller.Enemy.Location))
				{
					MGLostSightTimeout = 0.0;
					Controller.Focus = Controller.Enemy;
					Controller.FocalPoint = Controller.Enemy.Location;
				}
				else
				{
					MGLostSightTimeout = Level.TimeSeconds + (0.25 + FRand() * 0.35);
					Controller.Focus = None;
				}

				Controller.Target = Controller.Enemy;
			}
			else
			{
				MGLostSightTimeout = Level.TimeSeconds + (0.25 + FRand() * 0.35);
				Controller.Focus = None;
			}

			if( !bFireAtWill )
			{
				MGFireDuration = Level.TimeSeconds + (2.0 + FRand() * 1.5);
			}
			else if (	FRand() < 0.03 && Controller.Enemy != none && 
						PlayerController(Controller.Enemy.Controller) != none )
			{
				// Randomly send out a message about Patriarch shooting chain gun(3% chance)
				PlayerController(Controller.Enemy.Controller).Speech('AUTO', 9, "");
			}

			bFireAtWill = True;
			bShotAnim = true;
						//Acceleration = vect(0,0,0);

			SetAnimAction('FireMG');
			bWaitForAnim = true;
		}
	}

	function FireMGShot()
	{
		local vector Start,End,HL,HN,Dir;
		local rotator R;
		local Actor A;

		MGFireCounter--;

		if( AmbientSound != MiniGunFireSound )
		{
			SoundVolume=255;
			SoundRadius=400;
			AmbientSound = MiniGunFireSound;
		}

		Start = GetBoneCoords('tip').Origin;
		if( Controller.Focus!=None )
			R = rotator(Controller.Focus.Location-Start);
		else R = rotator(Controller.FocalPoint-Start);
		if( NeedToTurnFor(R) )
			R = Rotation;
		// KFTODO: Maybe scale this accuracy by his skill or the game difficulty
		Dir = Normal(vector(R)+VRand()*0.03);
		End = Start+Dir*95000;

		// Have to turn of hit point collision so trace doesn't hit the Human Pawn's bullet whiz cylinder
		bBlockHitPointTraces = false;
		A = Trace(HL,HN,End,Start,True);
		bBlockHitPointTraces = true;

		if( A==None )
			return;
		TraceHitPos = HL;
		if( Level.NetMode!=NM_DedicatedServer )
			AddTraceHitFX(HL);

		if( A!=Level )
		{
			A.TakeDamage(MGDamage+Rand(3),Self,HL,Dir*500,Class'DamageType');
		}
	}

	function bool NeedToTurnFor( rotator targ )
	{
		local int YawErr;

		targ.Yaw = DesiredRotation.Yaw & 65535;
		YawErr = (targ.Yaw - (Rotation.Yaw & 65535)) & 65535;
		return !((YawErr < 2000) || (YawErr > 64535));
	}

Begin:
	While( True )
	{

		//Acceleration = vect(0,0,0);

		if( MGLostSightTimeout > 0 && Level.TimeSeconds > MGLostSightTimeout )
		{
			bShotAnim = true;
			//Acceleration = vect(0,0,0);
			SetAnimAction('FireEndMG');
			HandleWaitForAnim('FireEndMG');
			GoToState('');
		}

		if( MGFireCounter <= 0 )
		{
			bShotAnim = true;
			Acceleration = vect(0,0,0);
			SetAnimAction('FireEndMG');
			HandleWaitForAnim('FireEndMG');
			GoToState('');
		}

		// Give some randomness to the patriarch's firing
		if( Level.TimeSeconds > MGFireDuration )
		{
			if( AmbientSound != MiniGunSpinSound )
			{
				SoundVolume=185;
				SoundRadius=200;
				AmbientSound = MiniGunSpinSound;
			}
			//Sleep(0.5 + FRand() * 0.75);
			Sleep(1.5 + FRand() * 1.0);
			MGFireDuration = Level.TimeSeconds + (2.00 + FRand() * 1.5);
		}
		else
		{
			if( bFireAtWill )
				FireMGShot();
			//Sleep(0.05);
				Sleep(0.2);
		}
	}
}

state FireMissile
{
Ignores RangedAttack;

	function bool ShouldChargeFromDamage()
	{
		return false;
	}

	function BeginState()
	{
		//Acceleration = vect(0,0,0);
	}

	function AnimEnd( int Channel )
	{
		local vector Start;
		local Rotator R;
		local SRKFHumanPawn HP;
		local bool bDirectEnemyGotShot;
		local float frandN;
		frandN=FRand();
		bDirectEnemyGotShot = false;
		//while (MissilesToShootInARow > 0)
		foreach VisibleCollidingActors(Class'SRKFHumanPawn',HP,1000,Location)
		{
		//if (MissilesToShootInARow < NumMissilesToShootInARow)
		//{
			//SetAnimAction('PreFireMissile');
			//HandleWaitForAnim('PreFireMissile');
		//}

			Start = GetBoneCoords('tip').Origin;
			if( Controller.Target==None )
			{
				Controller.Target = HP;
				Controller.Focus = HP;
			}
			if (HP == Controller.Enemy)
				bDirectEnemyGotShot = true;
			if ( !SavedFireProperties.bInitialized )
			{
				if(MyAmmo!=none)
				{
					SavedFireProperties.AmmoClass = MyAmmo.Class;
					SavedFireProperties.ProjectileClass = MyAmmo.ProjectileClass;
				}
				SavedFireProperties.WarnTargetPct = 0.15;
				SavedFireProperties.MaxRange = 10000;
				SavedFireProperties.bTossed = False;
				SavedFireProperties.bTrySplash = False;
				SavedFireProperties.bLeadTarget = True;
				SavedFireProperties.bInstantHit = True;
				SavedFireProperties.bInitialized = true;
			}

			//R = AdjustAim(SavedFireProperties,Start,100);
			R = AdjustAim(SavedFireProperties,Start,0);
			PlaySound(RocketFireSound,SLOT_Interact,2.0,,TransientSoundRadius,,false);
			//Log("frandNRocket="$frandN);
			if(frandN<0.10)
			{
				Spawn(Class'BossRocket2',,,Start,R);
			}
			else if(frandN>0.90)
			{
				Spawn(Class'BossRocket3',,,Start,R);
			}
			else
			{
				Spawn(Class'BossLAWProj',,,Start,R);
			}

			MissilesToShootInARow--;

			bShotAnim = true;
			//Acceleration = vect(0,0,0);
			SetAnimAction('FireEndMissile');
			HandleWaitForAnim('FireEndMissile');

			// Randomly send out a message about Patriarch shooting a rocket(5% chance)
			if ((MissilesToShootInARow + 1 == NumMissilesToShootInARow) && FRand() < 0.05 && 
				Controller.Enemy != none && PlayerController(Controller.Enemy.Controller) != none )
			{
				PlayerController(Controller.Enemy.Controller).Speech('AUTO', 10, "");
			}
			if (MissilesToShootInARow <= 0)
				break;
		}
		if (!bDirectEnemyGotShot)
		{
			//if (MissilesToShootInARow < NumMissilesToShootInARow)
			//{
			//SetAnimAction('PreFireMissile');
			//HandleWaitForAnim('PreFireMissile');
			//}

			Start = GetBoneCoords('tip').Origin;
			if( Controller.Target==None )
			{
				Controller.Target = Controller.Enemy;
				Controller.Focus = Controller.Enemy;
			}
			if ( !SavedFireProperties.bInitialized )
			{
				if(MyAmmo!=none)
				{
					SavedFireProperties.AmmoClass = MyAmmo.Class;
					SavedFireProperties.ProjectileClass = MyAmmo.ProjectileClass;
				}
				SavedFireProperties.WarnTargetPct = 0.15;
				SavedFireProperties.MaxRange = 10000;
				SavedFireProperties.bTossed = False;
				SavedFireProperties.bTrySplash = False;
				SavedFireProperties.bLeadTarget = True;
				SavedFireProperties.bInstantHit = True;
				SavedFireProperties.bInitialized = true;
			}

			//R = AdjustAim(SavedFireProperties,Start,100);
			R = AdjustAim(SavedFireProperties,Start,0);
			PlaySound(RocketFireSound,SLOT_Interact,2.0,,TransientSoundRadius,,false);
			//Log("frandNRocket2="$frandN);
			if(frandN<0.10)
			{
				Spawn(Class'BossRocket2',,,Start,R);
			}
			else if(frandN>0.90)
			{
				Spawn(Class'BossRocket3',,,Start,R);
			}
			else
			{
				Spawn(Class'BossLAWProj',,,Start,R);
			}
			MissilesToShootInARow--;

			bShotAnim = true;
			//Acceleration = vect(0,0,0);
			SetAnimAction('FireEndMissile');
			HandleWaitForAnim('FireEndMissile');
		}
		MissilesToShootInARow = 0;
		NumMissilesToShootInARow = 0;
		GoToState('');
	}
Begin:
	while ( true )
	{
		//Acceleration = vect(0,0,0);
		Sleep(0.1);
	}
}

function bool MeleeDamageTarget(int hitdamage, vector pushdir)
{
	if( Controller.Target!=None && Controller.Target.IsA('NetKActor') )
		pushdir = Normal(Controller.Target.Location-Location)*100000; // Fly bitch!

	// Used to set MeleeRange = Default.MeleeRange; in Balance Round 1, fixed in Balance Round 2

	return Super.MeleeDamageTarget(hitdamage, pushdir);
}

state Charging
{
	// Don't override speed in this state
	function bool CanSpeedAdjust()
	{
		return false;
	}

	function bool ShouldChargeFromDamage()
	{
		return false;
	}

	function BeginState()
	{
		bChargingPlayer = True;
		if( Level.NetMode!=NM_DedicatedServer )
			PostNetReceive();

		// How many charge attacks we can do randomly 1-4
		NumChargeAttacks = Rand(4) + 1;
	}

	function EndState()
	{
		GroundSpeed = GetOriginalGroundSpeed();
		bChargingPlayer = False;
		ChargeDamage = 0;
		if( Level.NetMode!=NM_DedicatedServer )
			PostNetReceive();

		LastChargeTime = Level.TimeSeconds;
	}

	function Tick( float Delta )
	{

		if( NumChargeAttacks <= 0 )
		{
			GoToState('');
		}

		// Keep the flesh pound moving toward its target when attacking
		if( Role == ROLE_Authority && bShotAnim)
		{
			if( bChargingPlayer )
			{
				bChargingPlayer = false;
				if( Level.NetMode!=NM_DedicatedServer )
					PostNetReceive();
			}
			GroundSpeed = OriginalGroundSpeed * 1.25;
			if( LookTarget!=None )
			{
				Acceleration = AccelRate * Normal(LookTarget.Location - Location);
			}
		}
		else
		{
			if( !bChargingPlayer )
			{
				bChargingPlayer = true;
				if( Level.NetMode!=NM_DedicatedServer )
					PostNetReceive();
			}

			GroundSpeed = OriginalGroundSpeed * 2.5;
		}


		Global.Tick(Delta);
	}

	function bool MeleeDamageTarget(int hitdamage, vector pushdir)
	{
		local bool RetVal;

		NumChargeAttacks--;

		RetVal = Global.MeleeDamageTarget(hitdamage, pushdir*1.5);
		if( RetVal )
			GoToState('');
		return RetVal;
	}

	function RangedAttack(Actor A)
	{
		if( VSize(A.Location-Location)>700 && Level.TimeSeconds - LastForceChargeTime > 3.0 )
			GoToState('');
		Global.RangedAttack(A);
	}
Begin:
	Sleep(6);
	GoToState('');
}

function BeginHealing()
{
	MonsterController(Controller).WhatToDoNext(55);
}


state Healing // Healing
{
	function bool ShouldChargeFromDamage()
	{
		return false;
	}

Begin:
	Sleep(GetAnimDuration('Heal'));
	GoToState('');
}

state KnockDown // Knocked
{
	function bool ShouldChargeFromDamage()
	{
		return false;
	}

Begin:
	if( Health > 0 )
	{
		Sleep(GetAnimDuration('KnockDown'));
		CloakBoss(0);
		PlaySound(sound'KF_EnemiesFinalSnd.Patriarch.Kev_SaveMe', SLOT_Misc, 2.0,,500.0);
		//PlaySound(sound'KF_EnemiesFinalSnd_Xmas.Patriarch.Kev_SaveMe', SLOT_Misc, 2.0,,500.0);
		if( KFGameType(Level.Game).FinalSquadNum == SyringeCount )
		{
			KFGameType(Level.Game).AddBossBuddySquad();
		}
		GotoState('Escaping');
	}
	else
	{
		GotoState('');
	}
}

State Escaping extends Charging // Got hurt and running away...
{
	function BeginHealing()
	{
		bShotAnim = true;
		Acceleration = vect(0,0,0);
		SetAnimAction('Heal');
		HandleWaitForAnim('Heal');
		GoToState('Healing');
	}

	function RangedAttack(Actor A)
	{
		if ( bShotAnim )
			return;
		else if ( IsCloseEnuf(A) )
		{
			if( bCloaked )
				UnCloakBoss();
			bShotAnim = true;
			//Acceleration = vect(0,0,0);
			Acceleration = (A.Location-Location);
			SetAnimAction('MeleeClaw');
			//PlaySound(sound'Claw2s', SLOT_None); Claw2s
		}
	}

	function bool MeleeDamageTarget(int hitdamage, vector pushdir)
	{
		return Global.MeleeDamageTarget(hitdamage, pushdir*1.5);
	}

	function Tick( float Delta )
	{

		// Keep the flesh pound moving toward its target when attacking
		if( Role == ROLE_Authority && bShotAnim)
		{
			if( bChargingPlayer )
			{
				bChargingPlayer = false;
				if( Level.NetMode!=NM_DedicatedServer )
					PostNetReceive();
			}
			GroundSpeed = GetOriginalGroundSpeed();
		}
		else
		{
			if( !bChargingPlayer )
			{
				bChargingPlayer = true;
				if( Level.NetMode!=NM_DedicatedServer )
					PostNetReceive();
			}

			GroundSpeed = OriginalGroundSpeed * 2.5;
		}


		Global.Tick(Delta);
	}

	function EndState()
	{
		GroundSpeed = GetOriginalGroundSpeed();
		bChargingPlayer = False;
		if( Level.NetMode!=NM_DedicatedServer )
			PostNetReceive();
		if( bCloaked )
			UnCloakBoss();
	}

Begin:
	While( true )
	{
		Sleep(0.5);
		if( !bCloaked && !bShotAnim )
			CloakBoss(0);
		if( !Controller.IsInState('SyrRetreat') && !Controller.IsInState('WaitForAnim'))
			Controller.GoToState('SyrRetreat');
	}
}

State SneakAround extends Escaping // Attempt to sneak around.
{
	function BeginHealing()
	{
		MonsterController(Controller).WhatToDoNext(56);
		GoToState('');
	}

	function bool MeleeDamageTarget(int hitdamage, vector pushdir)
	{
		local bool RetVal;

		RetVal = Super.MeleeDamageTarget(hitdamage, pushdir);

		GoToState('');
		return RetVal;
	}

	function BeginState()
	{
		Super.BeginState();
		SneakStartTime = Level.TimeSeconds;
	}

	function EndState()
	{
		Super.EndState();
		LastSneakedTime = Level.TimeSeconds;
	}


Begin:
	CloakBoss(0);
	While( true )
	{
		Sleep(0.5);

		if( Level.TimeSeconds - SneakStartTime > 10.0 )
		{
			GoToState('');
		}

		if( !bCloaked && !bShotAnim )
			CloakBoss(0);
		if( !Controller.IsInState('ZombieHunt') && !Controller.IsInState('WaitForAnim') )
		{
			Controller.GoToState('ZombieHunt');
		}
	}
}

State InitialSneak extends SneakAround // Sneak attack the players straight off the bat.
{
Begin:
	CloakBoss(0);
	While( true )
	{
		Sleep(0.5);
		SneakCount++;

		// Added sneakcount hack to try and fix the endless loop crash. Try and track down what was causing this later - Ramm
		if( SneakCount > 1000 || (Controller != none && EXBossZombieController(Controller).bAlreadyFoundEnemy) )
		{
			GoToState('');
		}

		if( !bCloaked && !bShotAnim )
			CloakBoss(0);
		if( !Controller.IsInState('InitialHunting') && !Controller.IsInState('WaitForAnim') )
		{
			Controller.GoToState('InitialHunting');
		}
	}
}

simulated function DropNeedle()
{
	if( CurrentNeedle!=None )
	{
		DetachFromBone(CurrentNeedle);
		CurrentNeedle.SetLocation(GetBoneCoords('Rpalm_MedAttachment').Origin);
		CurrentNeedle.DroppedNow();
		CurrentNeedle = None;
	}
}
simulated function NotifySyringeA()
{
	//log("Heal Part 1");

	if( Level.NetMode!=NM_Client )
	{
		if( SyringeCount<7 )
			SyringeCount++;
		if( Level.NetMode!=NM_DedicatedServer )
			PostNetReceive();
	}
	if( Level.NetMode!=NM_DedicatedServer )
	{
		DropNeedle();
		CurrentNeedle = Spawn(Class'BossHPNeedle');
		AttachToBone(CurrentNeedle,'Rpalm_MedAttachment');
	}
}
function NotifySyringeB()
{
	//log("Heal Part 2");
	if( Level.NetMode != NM_Client )
	{
		Health += HealingAmount;
		bHealed = true;
	}
}
simulated function NotifySyringeC()
{
	//log("Heal Part 3");
	if( Level.NetMode!=NM_DedicatedServer && CurrentNeedle!=None )
	{
		CurrentNeedle.Velocity = vect(-45,300,-90) >> Rotation;
		DropNeedle();
	}
}

simulated function PostNetReceive()
{
	if( bClientMiniGunning != bMinigunning )
	{
		bClientMiniGunning = bMinigunning;
		// Hack so Patriarch won't go out of MG Firing to play his idle anim online
		if( bMinigunning )
		{
			IdleHeavyAnim='FireMG';
			IdleRifleAnim='FireMG';
			IdleCrouchAnim='FireMG';
			IdleWeaponAnim='FireMG';
			IdleRestAnim='FireMG';
		}
		else
		{
			IdleHeavyAnim='BossIdle';
			IdleRifleAnim='BossIdle';
			IdleCrouchAnim='BossIdle';
			IdleWeaponAnim='BossIdle';
			IdleRestAnim='BossIdle';
		}
	}

	if( bClientCharg!=bChargingPlayer )
	{
		bClientCharg = bChargingPlayer;
		if (bChargingPlayer)
		{
			MovementAnims[0] = ChargingAnim;
			MovementAnims[1] = ChargingAnim;
			MovementAnims[2] = ChargingAnim;
			MovementAnims[3] = ChargingAnim;
		}
		else if( !bChargingPlayer )
		{
			MovementAnims[0] = default.MovementAnims[0];
			MovementAnims[1] = default.MovementAnims[1];
			MovementAnims[2] = default.MovementAnims[2];
			MovementAnims[3] = default.MovementAnims[3];
		}
	}
	else if( ClientSyrCount!=SyringeCount )
	{
		ClientSyrCount = SyringeCount;
		Switch( SyringeCount )
		{
			Case 2:
				SetBoneScale(3,0,'Syrange1');
				Break;
			Case 3:
			Case 4:
			Case 5:
				SetBoneScale(3,0,'Syrange1');
				SetBoneScale(4,0,'Syrange2');
				Break;
			Case 6:
				SetBoneScale(3,0,'Syrange1');
				SetBoneScale(4,0,'Syrange2');
				SetBoneScale(5,0,'Syrange3');
				Break;
			Default: // WTF? reset...?
				SetBoneScale(3,1,'Syrange1');
				SetBoneScale(4,1,'Syrange2');
				SetBoneScale(5,1,'Syrange3');
				Break;
		}
	}
	else if( TraceHitPos!=vect(0,0,0) )
	{
		AddTraceHitFX(TraceHitPos);
		TraceHitPos = vect(0,0,0);
	}
	else if( bClientCloaked!=bCloaked )
	{
		bClientCloaked = bCloaked;
		bCloaked = !bCloaked;
		if( bCloaked )
			UnCloakBoss();
		else CloakBoss(0);
		bCloaked = bClientCloaked;
	}
}

simulated function int DoAnimAction( name AnimName )
{
	if( AnimName=='MeleeImpale' || AnimName=='MeleeClaw' || AnimName=='transition' /*|| AnimName=='FireMG'*/  )
	{
		AnimBlendParams(1, 1.0, 0.0,, SpineBone1);
		PlayAnim(AnimName,, 0.1, 1);
		return 1;
	}
	return Super.DoAnimAction(AnimName);
}


simulated event SetAnimAction(name NewAction)
{
	local int meleeAnimIndex;

	if( NewAction=='' )
		return;
	if(NewAction == 'Claw')
	{
		meleeAnimIndex = Rand(3);
		NewAction = meleeAnims[meleeAnimIndex];
		CurrentDamtype = ZombieDamType[meleeAnimIndex];
	}

	ExpectingChannel = DoAnimAction(NewAction);

	if( Controller != none )
	{
		EXBossZombieController(Controller).AnimWaitChannel = ExpectingChannel;
	}

	if( AnimNeedsWait(NewAction) )
	{
		bWaitForAnim = true;
	}
	else
	{
		bWaitForAnim = false;
	}

	if( Level.NetMode!=NM_Client )
	{
		AnimAction = NewAction;
		bResetAnimAct = True;
		ResetAnimActTime = Level.TimeSeconds+0.3;
	}
}

// Hand sending the controller to the WaitForAnim state
simulated function HandleWaitForAnim( name NewAnim )
{
	local float RageAnimDur;

	Controller.GoToState('WaitForAnim');
	RageAnimDur = GetAnimDuration(NewAnim);
	EXBossZombieController(Controller).SetWaitForAnimTimout(RageAnimDur,NewAnim);
}

// The animation is full body and should set the bWaitForAnim flag
simulated function bool AnimNeedsWait(name TestAnim)
{
	if( /*TestAnim == 'MeleeImpale' || TestAnim =='MeleeClaw' || TestAnim =='transition' ||*/ 
		TestAnim == 'FireMG' || TestAnim == 'PreFireMG' || TestAnim == 'PreFireMissile' || 
		TestAnim == 'FireEndMG'|| TestAnim == 'FireEndMissile' || TestAnim == 'Heal' || 
		TestAnim == 'KnockDown' || TestAnim == 'Entrance' || TestAnim == 'VictoryLaugh' )
	{
		return true;
	}

	return false;
}

simulated function HandleBumpGlass()
{
}


function bool FlipOver()
{
	return False;
}

// return true if we want to charge from taking too much damage
function bool ShouldChargeFromDamage()
{
	// If we don;t want to heal, charge whoever damaged us!!!
	if( (SyringeCount==0 && Health<HealingLevels[0]) || 
		(SyringeCount==1 && Health<HealingLevels[1]) || 
		(SyringeCount==2 && Health<HealingLevels[2]) ||
		(SyringeCount==3 && Health<HealingLevels[3]) || 
		(SyringeCount==4 && Health<HealingLevels[4]) || 
		(SyringeCount==5 && Health<HealingLevels[5]) ||
		(SyringeCount==6 && Health<HealingLevels[6])
	)
	{
		return false;
	}
	else if( !bChargingPlayer && Level.TimeSeconds - LastForceChargeTime > (5.0 + 5.0 * FRand()) )
	{
		return true;
	}
	return false;
}

function TakeDamage( int Damage, Pawn InstigatedBy, Vector Hitlocation, Vector Momentum, class<DamageType> damageType, optional int HitIndex)
{
	local float DamagerDistSq;
	local PlayerDamageStruct PDS;
	local int i;
	local bool isNewElement;
	local float oldH, oldHH;
	//log(GetStateName()$" Took damage. Health="$Health$" Damage = "$Damage$" HealingLevels "$HealingLevels[SyringeCount]);
//	Log("Ex TakeDamage="$damageType@Damage);
	if ( class<DamTypeCrossbow>(damageType) == none && class<DamTypeCrossbowHeadShot>(damageType) == none )
	{
		bOnlyDamagedByCrossbow = false;
	}
	if ( class<DamTypeSCrossbowW>(damageType) != none || class<DamTypeSCrossbowWHeadShot>(damageType) != none )
	{
		Damage *= 0.05;
	}
	else if ( class<DamTypeM99WHeadShot>(damageType) != none )
	{
		Damage *= 0.50;
	}
	else if ( class<DamTypeHuntingRifleW>(damageType) != none)
	{
		Damage *= 0.40;
	}
	else if ( class<DamTypeProtectaW>(damageType) != none)
	{
		Damage *= 0.15;
	}
	else if ( 	class<DamTypeRocketImpactW>(damageType) != none || 
				class<DamTypeLawRocketImpactW>(damageType) != none)
	{
		Damage *= 0.35;
	}
	else if ( class<DamTypeCrossbow>(damageType) != none || class<DamTypeCrossbowHeadShot>(damageType) != none )
	{
	}
	else if ( 	class<DamTypePipeBomb>(damageType) != none || 
				class<DamTypePipeBombW>(damageType) != none ||
				class<DamTypeBigPipeBombW>(damageType) != none ||
				class<DamTypeVeryBigPipeBombW>(damageType) != none)
	{
		if (SRKFHumanPawn(InstigatedBy) != none && KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo) != none && KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkill != none)
		{
			if ( KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkill == class'SRVetDemolitions' )
			{
				if ( KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkillLevel > 10 )
					Damage *= 0.03;
				else if ( KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkillLevel > 7 )
					Damage *= 0.07;
				else if ( KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkillLevel > 5 )
					Damage *= 0.15;
				else
					Damage *= 0.3;
			}
		}
	}
	
	else if ( 	class<DamTypeWeakNadeW>(damageType) != none || 
				class<DamTypeFrag>(damageType) != none ||
				class<DamTypeFragW>(damageType) != none 
			)
	{
		if ( KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkill == class'SRVetDemolitions' )
		{
			if ( KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkillLevel > 12 )
				Damage *= 0.5;
			else if ( KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkillLevel > 11 )
				Damage *= 0.6;
			else if ( KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkillLevel > 7 )
				Damage *= 0.7;
			else if ( KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkillLevel > 5 )
				Damage *= 0.8;
			else
				Damage *= 0.9;
		}
	}
	
	else if ( 	class<DamTypeFireBombW>(damageType) != none || 
				class<DamTypeFlameNade>(damageType) != none || 
				class<DamTypeFlameNadeW>(damageType) != none ||
				class<DamTypeHuskGunW>(damageType) != none ||
				class<DamTypeHuskGunProjectileImpactW>(damageType) != none ||
				class<DamTypeBurned>(damageType) != none ||
				class<DamTypeBurnedW>(damageType) != none ||
				class<DamTypeFlameThrower>(damageType) != none ||
				class<DamTypeFlameThrowerW>(damageType) != none 
			)
	{
		if ( KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkill == class'SRVetFirebug' )
		{
			if ( KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkillLevel > 12 )
				Damage *= 0.35;
			else if ( KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkillLevel > 10 )
				Damage *= 0.40;
			else if ( KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkillLevel > 7 )
				Damage *= 0.50;
			else if ( KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkillLevel > 5 )
				Damage *= 0.55;
			else
				Damage *= 0.60;
		}
		else
		{
			Damage *= 0.40;
		}
	}
/* 	else if ( class<DamTypeFrag>(damageType) != none || class<DamTypeM32Grenade>(damageType) != none ||
			class<DamTypeM79Grenade>(damageType) != none || class<DamTypeLAW>(damageType) != none ||
			class<DamTypeLawRocketImpact>(damageType) != none )
	{
		if (SRKFHumanPawn(InstigatedBy) != none && KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo) != none && KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkill != none)
		{
			if ( KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkill == class'SRVetDemolitions' )
			{
				if ( KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkillLevel > 10 )
					Damage *= 0.04;
				else if ( KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkillLevel > 7 )
					Damage *= 0.08;
				else if ( KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkillLevel > 5 )
					Damage *= 0.1;
				else
					Damage *= 0.4;
			}
		}
	} */
	else if (	class<DamTypeAA12Shotgun>(damageType) != none || 
				class<DamTypeAA12ShotgunW>(damageType) != none || 
				class<DamTypeShotgun>(damageType) != none ||
				class<DamTypeShotgunW>(damageType) != none
			)
	{
		Damage *= 0.5;
	}

	else if (	damageType.Name == 'DamTypeM41AW' || 
				class<DamTypeFnFalW>(damageType) != none || 
				class<DamTypeM4W>(damageType) != none ||
				class<DamTypeSCARMK17AssaultRifle>(damageType) != none ||
				class<DamTypeSCARMK17W>(damageType) != none
			)
	{
		Damage *= 0.4;
	}

	else if (class<DamTypeMG34W>(damageType) != none || class<DamTypePKM>(damageType) != none)
	{
		Damage *= 0.30;
	}

	else if (	class<DamTypeDBShotgun>(damageType) != none ||
				class<DamTypeDBShotgunW>(damageType) != none)
	{
		if (SRKFHumanPawn(InstigatedBy) != none && 
			KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo) != none && 
			KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkill != none)
		{
			if ( KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkill == class'SRVetSupportSpec' )
			{
				if ( KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkillLevel > 11 )
					Damage *= 0.4;
			}
		}
	}

/* 	else if ( class<DamTypeBurned>(damageType) != none  || class<DamTypeBurnedW>(damageType) != none)
	{
		if ( KFPlayerReplicationInfo(SRKFHumanPawn(InstigatedBy).PlayerReplicationInfo).ClientVeteranSkillLevel > 11 )
			Damage *= 0.1;
		else
			Damage *= 0.6;
	} */
/* 	else if ( 	class<DamTypeFlameThrower>(damageType) != none ||
				class<DamTypeFlameThrowerW>(damageType) != none	)
	{
		//Log("DamTypeFlameThrower Damage="$Damage);
		Damage *= 0.2;
	} */
/* 	else if ( class<DamTypeFlameNade>(damageType) != none )
	{
		Log("DamTypeFlameNade Damage="$Damage);
		Damage *= 0.1;
	} */
	else if( class<DamTypeMelee>(damageType) != none )
	{
		Damage *= 0.75;
	}
	else if (	class<DamTypeRaijinW>(damageType) != none ||
				class<DamTypePG>(damageType) != none)
	{
		Damage *= 0.1;
	}
	
	oldH=Health;
	oldHH=HeadHealth;
	if(IsHeadShot(Hitlocation, Normal(Momentum), 1.0))
		Log("ExZBSTATE"@GetStateName()@Controller.GetStateName()@Damage@damageType@InstigatedBy.OwnerName);
	//Log(self$"   HealthBefore="$Health$"   HeadHealthBefore="$HeadHealth);
	Super.TakeDamage(Damage,instigatedBy,hitlocation,Momentum,damageType);
	//Log("HealthTaken="$oldH-Health$"   HeadHealthTaken="$oldHH-HeadHealth);
	
	isNewElement=true;
	if(InstigatedBy!=None)
	{
		PDS.PlayerName=InstigatedBy.Controller.PlayerReplicationInfo.PlayerName;
		if(Health<=0)
		{
			PDS.Damage=oldH;
		}
		else
		{
			PDS.Damage=oldH-Health;
		}
		//PlayerDamageStructArray.Insert(PDS);
	
		for(i=0;i<PlayerDamageStructArray.Length;i++)
		{
			if(PlayerDamageStructArray[i].PlayerName==PDS.PlayerName)
			{
				PlayerDamageStructArray[i].Damage+=PDS.Damage;
				isNewElement=false;
			}
		}
	
		if(isNewElement && Len(PDS.PlayerName)>0)
		{
			PlayerDamageStructArray[PlayerDamageStructArray.Length]=PDS;
		}
	}
	//Log(self$"   HealthBefore="$Health);
	
	//Log("PatD="$Damage);
	

	
/*  	for(i=0;i<PlayerDamageStructArray.Length;i++)
	{
		Log(PlayerDamageStructArray[i].PlayerName@"made"@PlayerDamageStructArray[i].Damage);
	} 
	
*/
	if( Level.TimeSeconds - LastDamageTime > 10 )
	{
		ChargeDamage = 0;
	}
	else
	{
		LastDamageTime = Level.TimeSeconds;
		ChargeDamage += Damage;
	}

	if( ShouldChargeFromDamage() && ChargeDamage > 200 )
	{
		// If someone close up is shooting us, just charge them
		if( InstigatedBy != none )
		{
			DamagerDistSq = VSizeSquared(Location - InstigatedBy.Location);
			if( DamagerDistSq < (700 * 700) )
			{
				SetAnimAction('transition');
				ChargeDamage=0;
				LastForceChargeTime = Level.TimeSeconds;
				GoToState('Charging');
				return;
			}
		}
	}

	if( Health<=0 || SyringeCount==7 || IsInState('Escaping') || IsInState('KnockDown') /*|| bShotAnim*/ )
		return;

	if( (SyringeCount==0 && Health<HealingLevels[0]) || (SyringeCount==1 && Health<HealingLevels[1]) || 
		(SyringeCount==2 && Health<HealingLevels[2]) || (SyringeCount==3 && Health<HealingLevels[3]) || 
		(SyringeCount==4 && Health<HealingLevels[4]) || (SyringeCount==5 && Health<HealingLevels[5]) ||
		(SyringeCount==6 && Health<HealingLevels[6])
		)
	{
		//log(GetStateName()$" Took damage and want to heal!!! Health="$Health$" HealingLevels "$HealingLevels[SyringeCount]);
		bShotAnim = true;
		Acceleration = vect(0,0,0);
		SetAnimAction('KnockDown');
		HandleWaitForAnim('KnockDown');
		SRMonsterController(Controller).bUseFreezeHack = True;
		GoToState('KnockDown');
	}
}

function DoorAttack(Actor A)
{
	if ( bShotAnim )
		return;
	else if ( A!=None )
	{
		if (MissilesToShootInARow <= 0)
		{
			NumMissilesToShootInARow = 3 + rand(4);
			MissilesToShootInARow = NumMissilesToShootInARow;
		}
		Controller.Target = A;
		bShotAnim = true;
		Acceleration = vect(0,0,0);
		SetAnimAction('PreFireMissile');
		HandleWaitForAnim('PreFireMissile');
		GoToState('FireMissile');
	}
}

function RemoveHead();
function PlayDirectionalHit(Vector HitLoc);
function bool SameSpeciesAs(Pawn P)
{
	return False;
}

// Creapy endgame camera when the evil wins.
function bool SetBossLaught()
{
	local Controller C;

	GoToState('');
	bShotAnim = true;
	Acceleration = vect(0,0,0);
	SetAnimAction('VictoryLaugh');
	HandleWaitForAnim('VictoryLaugh');
	bIsBossView = True;
	bSpecialCalcView = True;
	for( C=Level.ControllerList; C!=None; C=C.NextController )
	{
		if( PlayerController(C)!=None )
		{
			PlayerController(C).SetViewTarget(Self);
			PlayerController(C).ClientSetViewTarget(Self);
			PlayerController(C).ClientSetBehindView(True);
		}
	}
	return True;
}
simulated function bool SpectatorSpecialCalcView(PlayerController Viewer, out Actor ViewActor, out vector CameraLocation, out rotator CameraRotation)
{
	Viewer.bBehindView = True;
	ViewActor = Self;
	CameraRotation.Yaw = Rotation.Yaw-32768;
	CameraRotation.Pitch = 0;
	CameraRotation.Roll = Rotation.Roll;
	CameraLocation = Location + (vect(80,0,80) >> Rotation);
	return True;
}

// Overridden to do a cool slomo death view of the patriarch dying
function Died(Controller Killer, class<DamageType> damageType, vector HitLocation)
{
	local Controller C;
	local float frandN;
	//PlaySound(sound'KF_EnemiesFinalSnd.Kev_WarnGun', SLOT_Misc, 10.0,,5000.0);
	//PlaySound(Sound'BomberSounds.Timer', , 10.0, , 5000.0);
	
	Super.Died(Killer,damageType,HitLocation);
	frandN=FRand();
	Log("frandN="$frandN);
	if(frandN<0.3)
	{
/* 		for (C = Level.ControllerList; C != None; C = C.NextController)
		{
			if(C.IsA('PlayerController'))
			{
				PlayerController(C).ReceiveLocalizedMessage(class'AprilInfoMessage', 4);
			}
		} */
		//Spawn(Class'BossWTFProj');
	}
	if(frandN>0.8)
	{
/* 		for (C = Level.ControllerList; C != None; C = C.NextController)
		{
			if(C.IsA('PlayerController'))
			{
				PlayerController(C).ReceiveLocalizedMessage(class'AprilInfoMessage', 5);
			}
		} */

		//Spawn(Class'BossBlackHoleProj');
		//Spawn(Class'BossBlackHoleProj');
	}

	
	KFGameType(Level.Game).DoBossDeath();
	for( C=Level.ControllerList; C!=None; C=C.NextController )
	{
		if( PlayerController(C)!=None )
		{
			PlayerController(C).SetViewTarget(Self);
			PlayerController(C).ClientSetViewTarget(Self);
			PlayerController(C).bBehindView = true;
			PlayerController(C).ClientSetBehindView(True);
		}
	}
}

function ClawDamageTarget()
{
	local vector PushDir;
	local name Anim;
	local float frame,rate;
	local float UsedMeleeDamage;
	local bool bDamagedSomeone;
	local KFHumanPawn P;
	local Actor OldTarget;

	if( MeleeDamage > 1 )
	{
		UsedMeleeDamage = (MeleeDamage - (MeleeDamage * 0.05)) + (MeleeDamage * (FRand() * 0.1));
	}
	else
	{
		UsedMeleeDamage = MeleeDamage;
	}

	GetAnimParams(1, Anim,frame,rate);

	if( Anim == 'MeleeImpale' )
	{
		MeleeRange = ImpaleMeleeDamageRange;
	}
	else
	{
		MeleeRange = ClawMeleeDamageRange;
	}

	if(Controller!=none && Controller.Target!=none)
		PushDir = (damageForce * Normal(Controller.Target.Location - Location));
	else
		PushDir = damageForce * vector(Rotation);

// Begin Balance Round 1(damages everyone in Round 2 and added seperate code path for MeleeImpale in Round 3)
	if( Anim == 'MeleeImpale' )
	{
		bDamagedSomeone = MeleeDamageTarget(UsedMeleeDamage, PushDir);
	}
	else
	{
		OldTarget = Controller.Target;

		foreach DynamicActors(class'KFHumanPawn', P)
		{
			if ( (P.Location - Location) dot PushDir > 0.0 ) // Added dot Product check in Balance Round 3
			{
				Controller.Target = P;
				bDamagedSomeone = bDamagedSomeone || MeleeDamageTarget(UsedMeleeDamage, damageForce * Normal(P.Location - Location)); // Always pushing players away added in Balance Round 3
			}
		}

		Controller.Target = OldTarget;
	}

	MeleeRange = Default.MeleeRange;
// End Balance Round 1, 2, and 3

	if ( bDamagedSomeone )
	{
		if( Anim == 'MeleeImpale' )
		{
			PlaySound(MeleeImpaleHitSound, SLOT_Interact, 2.0);
		}
		else
		{
			PlaySound(MeleeAttackHitSound, SLOT_Interact, 2.0);
		}
	}
}

simulated function ProcessHitFX()
{
	local Coords boneCoords;
	local class<xEmitter> HitEffects[4];
	local int i,j;
	local float GibPerterbation;

	if( (Level.NetMode == NM_DedicatedServer) || bSkeletized || (Mesh == SkeletonMesh))
	{
		SimHitFxTicker = HitFxTicker;
		return;
	}

	for ( SimHitFxTicker = SimHitFxTicker; SimHitFxTicker != HitFxTicker; SimHitFxTicker = (SimHitFxTicker + 1) % ArrayCount(HitFX) )
	{
		j++;
		if ( j > 30 )
		{
			SimHitFxTicker = HitFxTicker;
			return;
		}

		if( (HitFX[SimHitFxTicker].damtype == None) || (Level.bDropDetail && (Level.TimeSeconds - LastRenderTime > 3) && !IsHumanControlled()) )
			continue;

		//log("Processing effects for damtype "$HitFX[SimHitFxTicker].damtype);

		if( HitFX[SimHitFxTicker].bone == 'obliterate' && !class'GameInfo'.static.UseLowGore())
		{
			SpawnGibs( HitFX[SimHitFxTicker].rotDir, 1);
			bGibbed = true;
			Destroy();
			return;
		}

		boneCoords = GetBoneCoords( HitFX[SimHitFxTicker].bone );

		if ( !Level.bDropDetail && !class'GameInfo'.static.NoBlood() && !bSkeletized && !class'GameInfo'.static.UseLowGore() )
		{
			//AttachEmitterEffect( BleedingEmitterClass, HitFX[SimHitFxTicker].bone, boneCoords.Origin, HitFX[SimHitFxTicker].rotDir );

			HitFX[SimHitFxTicker].damtype.static.GetHitEffects( HitEffects, Health );

			if( !PhysicsVolume.bWaterVolume ) // don't attach effects under water
			{
				for( i = 0; i < ArrayCount(HitEffects); i++ )
				{
					if( HitEffects[i] == None )
						continue;

					AttachEffect( HitEffects[i], HitFX[SimHitFxTicker].bone, boneCoords.Origin, HitFX[SimHitFxTicker].rotDir );
				}
			}
		}
		if ( class'GameInfo'.static.UseLowGore() )
			HitFX[SimHitFxTicker].bSever = false;

		if( HitFX[SimHitFxTicker].bSever )
		{
			GibPerterbation = HitFX[SimHitFxTicker].damtype.default.GibPerterbation;

			switch( HitFX[SimHitFxTicker].bone )
			{
				case 'obliterate':
					break;

				case LeftThighBone:
					if( !bLeftLegGibbed )
					{
						SpawnSeveredGiblet( DetachedLegClass, boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation, GetBoneRotation(HitFX[SimHitFxTicker].bone) );
						KFSpawnGiblet( class 'KFMod.KFGibBrain',boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation, 250 ) ;
						KFSpawnGiblet( class 'KFMod.KFGibBrainb',boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation, 250 ) ;
						KFSpawnGiblet( class 'KFMod.KFGibBrain',boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation, 250 ) ;
						bLeftLegGibbed=true;
					}
					break;

				case RightThighBone:
					if( !bRightLegGibbed )
					{
						SpawnSeveredGiblet( DetachedLegClass, boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation, GetBoneRotation(HitFX[SimHitFxTicker].bone) );
						KFSpawnGiblet( class 'KFMod.KFGibBrain',boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation, 250 ) ;
						KFSpawnGiblet( class 'KFMod.KFGibBrainb',boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation, 250 ) ;
						KFSpawnGiblet( class 'KFMod.KFGibBrain',boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation, 250 ) ;
						bRightLegGibbed=true;
					}
					break;

				case LeftFArmBone:
					if( !bLeftArmGibbed )
					{
						SpawnSeveredGiblet( DetachedSpecialArmClass, boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation, GetBoneRotation(HitFX[SimHitFxTicker].bone) );
						KFSpawnGiblet( class 'KFMod.KFGibBrain',boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation, 250 ) ;
						KFSpawnGiblet( class 'KFMod.KFGibBrainb',boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation, 250 ) ;;
						bLeftArmGibbed=true;
					}
					break;

				case RightFArmBone:
					if( !bRightArmGibbed )
					{
						SpawnSeveredGiblet( DetachedArmClass, boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation, GetBoneRotation(HitFX[SimHitFxTicker].bone) );
						KFSpawnGiblet( class 'KFMod.KFGibBrain',boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation, 250 ) ;
						KFSpawnGiblet( class 'KFMod.KFGibBrainb',boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation, 250 ) ;
						bRightArmGibbed=true;
					}
					break;

				case 'head':
					if( !bHeadGibbed )
					{
						if ( HitFX[SimHitFxTicker].damtype == class'DamTypeDecapitation' )
						{
							DecapFX( boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, false);
						}
						else if( HitFX[SimHitFxTicker].damtype == class'DamTypeMeleeDecapitation' )
						{
							DecapFX( boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, true);
						}

						bHeadGibbed=true;
					}
					break;
			}


			if( HitFX[SimHitFXTicker].bone != 'Spine' && HitFX[SimHitFXTicker].bone != FireRootBone &&
				HitFX[SimHitFXTicker].bone != 'head' && Health <=0 )
				HideBone(HitFX[SimHitFxTicker].bone);
		}
	}
}

// Maybe Spawn some chunks when the player gets obliterated
simulated function SpawnGibs(Rotator HitRotation, float ChunkPerterbation)
{
	bGibbed = true;
	PlayDyingSound();

	if ( class'GameInfo'.static.UseLowGore() )
		return;

	if( ObliteratedEffectClass != none )
		Spawn( ObliteratedEffectClass,,, Location, HitRotation );

	Super.SpawnGibs(HitRotation,ChunkPerterbation);

	if ( FRand() < 0.1 )
	{
		KFSpawnGiblet( class 'KFMod.KFGibBrain',Location, HitRotation, ChunkPerterbation, 500 ) ;
		KFSpawnGiblet( class 'KFMod.KFGibBrainb',Location, HitRotation, ChunkPerterbation, 500 ) ;
		KFSpawnGiblet( class 'KFMod.KFGibBrain',Location, HitRotation, ChunkPerterbation, 500 ) ;
		KFSpawnGiblet( class 'KFMod.KFGibBrainb',Location, HitRotation, ChunkPerterbation, 500 ) ;
		KFSpawnGiblet( class 'KFMod.KFGibBrain',Location, HitRotation, ChunkPerterbation, 500 ) ;

		SpawnSeveredGiblet( DetachedLegClass, Location, HitRotation, ChunkPerterbation, HitRotation );
		SpawnSeveredGiblet( DetachedLegClass, Location, HitRotation, ChunkPerterbation, HitRotation );
		SpawnSeveredGiblet( DetachedSpecialArmClass, Location, HitRotation, ChunkPerterbation, HitRotation );
		SpawnSeveredGiblet( DetachedArmClass, Location, HitRotation, ChunkPerterbation, HitRotation );
	}
	else if ( FRand() < 0.25 )
	{
		KFSpawnGiblet( class 'KFMod.KFGibBrainb',Location, HitRotation, ChunkPerterbation, 500 ) ;
		KFSpawnGiblet( class 'KFMod.KFGibBrain',Location, HitRotation, ChunkPerterbation, 500 ) ;
		KFSpawnGiblet( class 'KFMod.KFGibBrainb',Location, HitRotation, ChunkPerterbation, 500 ) ;
		KFSpawnGiblet( class 'KFMod.KFGibBrain',Location, HitRotation, ChunkPerterbation, 500 ) ;

		SpawnSeveredGiblet( DetachedLegClass, Location, HitRotation, ChunkPerterbation, HitRotation );
		SpawnSeveredGiblet( DetachedLegClass, Location, HitRotation, ChunkPerterbation, HitRotation );
		if ( FRand() < 0.5 )
		{
			KFSpawnGiblet( class 'KFMod.KFGibBrain',Location, HitRotation, ChunkPerterbation, 500 ) ;
			SpawnSeveredGiblet( DetachedArmClass, Location, HitRotation, ChunkPerterbation, HitRotation );
		}
	}
	else if ( FRand() < 0.35 )
	{
		KFSpawnGiblet( class 'KFMod.KFGibBrainb',Location, HitRotation, ChunkPerterbation, 500 ) ;
		KFSpawnGiblet( class 'KFMod.KFGibBrain',Location, HitRotation, ChunkPerterbation, 500 ) ;
		SpawnSeveredGiblet( DetachedLegClass, Location, HitRotation, ChunkPerterbation, HitRotation );
	}
	else if ( FRand() < 0.5 )
	{
		KFSpawnGiblet( class 'KFMod.KFGibBrainb',Location, HitRotation, ChunkPerterbation, 500 ) ;
		KFSpawnGiblet( class 'KFMod.KFGibBrain',Location, HitRotation, ChunkPerterbation, 500 ) ;
		SpawnSeveredGiblet( DetachedArmClass, Location, HitRotation, ChunkPerterbation, HitRotation );
	}
}

defaultproperties
{
     DetachedArmClass=Class'KFChar.SeveredArmPatriarch'
     DetachedLegClass=Class'KFChar.SeveredLegPatriarch'
     DetachedHeadClass=Class'KFChar.SeveredHeadPatriarch'
     DetachedSpecialArmClass=Class'KFChar.SeveredRocketArmPatriarch'
     ControllerClass=Class'PerksSimHostOrg.EXBossZombieController'
}
